<?php

namespace common\base;

use Yii;
use yii\base\NotSupportedException;
use yii\web\IdentityInterface;
use yii\filters\RateLimitInterface;
use common\validators\MobileValidator;
use common\helpers\Url;
use common\helpers\StringHelper;
use yii\helpers\ArrayHelper;

/**
 * 用户身份信息基类
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
abstract class User extends BaseUser implements IdentityInterface, RateLimitInterface {

    use \common\traits\Constants;

    const STATUS_ACTIVE = 10;
    const STATUS_DEFAULT = 0;
    const STATUS_DELETED = -1;
    const PASSWORD_RESET_TOKEN_EXPIRE_DURATION = 3600;

    /**
     * {@inheritdoc}
     */
    public static function tableName() {
        return '{{%user}}';
    }

    /**
     * 返回在单位时间内允许的请求的最大数目，例如，[10, 60] 表示在60秒内最多请求10次。
     * @return type
     */
    public function getAllowance() {
        return Yii::$app->cache->get($this->id . '_allowance');
    }

    /**
     * 返回更新时间
     * @return type
     */
    public function getAllowanceUpdatedAt() {
        return Yii::$app->cache->get($this->id . '_allowance_updated_at');
    }

    /**
     * 返回在单位时间内允许的请求的最大数目，例如，[10, 60] 表示在60秒内最多请求10次。
     * @inheritdoc
     * @return type
     */
    public function getRateLimit($request, $action) {
        return [20, 1];
    }

    /**
     * 返回剩余的允许的请求数
     * @inheritdoc
     * @return type
     */
    public function loadAllowance($request, $action) {
        return [$this->allowance, $this->allowanceUpdatedAt];
    }

    /**
     * 保存请求时的UNIX时间戳
     * @inheritdoc
     * @return type
     */
    public function saveAllowance($request, $action, $allowance, $timestamp) {
        Yii::$app->cache->set($this->id . '_allowance', $allowance);
        Yii::$app->cache->set($this->id . '_allowance_updated_at', $timestamp);
    }

    /**
     * 通过给定ID查找身份 
     * @inheritdoc
     */
    public static function findIdentity($id) {
        return static::findOne([
            'id' => $id,
            'deleted_at' => null
        ]);
    }

    /**
     * 通过给定令牌查找用户身份标识
     * @inheritdoc
     */
    public static function findIdentityByAccessToken($token, $type = null) {
        throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
    }

    /**
     * 通过给定用户名查找用户
     * @param string $username
     * @return static|null
     */
    public static function findByUsername($username) {
        return static::findOne([
            'username' => $username,
            'deleted_at' => 0
        ]);
    }

    /**
     * 根据手机号查询用户信息
     * @param string $mobile
     * @return static|null
     */
    public static function findByMobile($mobile) {
        $entra = Yii::$app->security->generatePrivateKey($mobile);
        return static::findOne([
            'mobile' => $entra,
            'deleted_at' => 0
        ]);
    }

    /**
     * 通过用户名、手机号或者邮箱查询用户
     * @param string $account 用户名、手机号或者邮箱
     * @return static|null
     */
    public static function findByAccount($account) {
        $query = static::find()->active(self::STATUS_ACTIVE);
        $condition = [
            'or',
            ['username' => $account]
        ];
        if (is_numeric($account)) {
            $valid = new MobileValidator();
            if ($valid->validate($account)) {
                $mobile = Yii::$app->security->generatePrivateKey($account);
                $condition[] = ['mobile' => $mobile];
            }
        }
        return $query->andWhere($condition)->one();
    }

    /**
     * 通过给定密码重置TOKEN查找用户
     * @param string $token password reset token
     * @return static|null
     */
    public static function findByPasswordResetToken($token) {
        if (!static::isPasswordResetTokenValid($token)) {
            return null;
        }
        return static::findOne([
            'password_reset_token' => $token,
            'deleted_at' => null
        ]);
    }

    /**
     * 校验密码重置TOKEN是否有效
     * @param string $token password reset token
     * @return boolean
     */
    public static function isPasswordResetTokenValid($token) {
        if (empty($token)) {
            return false;
        }
        $timestamp = (int) substr($token, strrpos($token, '_') + 1);
        $expire = static::PASSWORD_RESET_TOKEN_EXPIRE_DURATION;
        return $timestamp + $expire >= time();
    }

    /**
     * 返回可用于检查给定身份ID的有效性的密钥 
     * @inheritdoc
     */
    public function getAuthKey() {
        return $this->auth_key;
    }

    /**
     * 验证给定的AUTH密钥
     * @inheritdoc
     */
    public function validateAuthKey($authKey) {
        return $this->getAuthKey() === $authKey;
    }

    /**
     * 生成“记住密码”时的认证密钥 
     */
    public function generateAuthKey() {
        $this->auth_key = Yii::$app->security->generateRandomString();
    }

    /**
     * 通过哈希验证密码 
     * @param string $password password to validate
     * @return boolean if password provided is valid for current user
     */
    public function validatePassword($password) {
        return Yii::$app->security->validatePassword($password, $this->password_hash);
    }

    /**
     * 从口令生成哈希密码并将其赋值给当前模型的密码变量
     * @param string $password
     */
    public function setPassword($password) {
        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
    }

    /**
     * 生成新的密码重置令牌
     */
    public function generatePasswordResetToken() {
        $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
    }

    /**
     * 删除密码重置令牌
     */
    public function removePasswordResetToken() {
        $this->password_reset_token = null;
    }

    /**
     * 设置手机号
     * @param string $mobile
     */
    public function setMobile($mobile) {
        if ($mobile) {
            /* @var $security \common\base\Security */
            $security = Yii::$app->security;
            $this->mobile_hash = $security->encryptMaster($mobile);
        }
    }

    /**
     * 解密手机号
     * @param boolean $mask
     * @return string 手机号
     */
    public function decryptMobile($mask = true) {
        /* @var $security \common\base\Security */
        $security = Yii::$app->security;
        $mobile = $security->decryptMaster($this->mobile_hash);
        if ($mask !== false) {
            return StringHelper::maskChar($mobile, 3, 2);
        }
        return $mobile;
    }

    public function getDefaultAvatar() {
        $avatar = '';
        return ArrayHelper::getValue(Yii::$app->params, 'defaultImages.user_avatar', $avatar);
    }

    /**
     * 获取用户头像
     * @return string
     */
    public function getAvatar() {
        $avatar = $this->portrait;
        if (!$avatar) {
            $avatar = $this->defaultAvatar;
        }
        return Url::attachAvatar($avatar);
    }

    /**
     * 获取头像URL
     * @return string
     */
    public function getPortrait() {
        return $this->getAvatar();
    }

    /**
     * 获取用户名
     * @return string
     */
    public function getUserName() {
        if ($this->realname) {
            return $this->realname;
        }
        if ($this->nickname) {
            return $this->nickname;
        }
        return $this->username;
    }

    /**
     * 获取用户ID
     * @return integer
     */
    public function getUserId() {
        return $this->getPrimaryKey();
    }

    /**
     * 获取根ID
     * @return integer
     */
    public function getRootId() {
        return $this->root_id;
    }

    /**
     * 获取用户基础信息
     * @return \yii\db\ActiveQuery
     */
    public function getAccount() {
        return $this->hasOne(\common\logics\UserAccountLogic::class, ['user_id' => 'id']);
    }

    /**
     * 获取用户积分账户余额
     * @return integer
     */
    public function getPoints() {
        if ($this->account) {
            return $this->account->credit;
        }
        return 0;
    }

}
